/*
 * (C) Copyright 2015 Linaro
 * Peter Griffin <peter.griffin@linaro.org>
 *
 * SPDX-License-Identifier: GPL-2.0+
 */
#include <config.h>
#include <common.h>
#include <asm/io.h>
#include <asm/arch/platform.h>
#include <spi_flash.h>
#include <linux/mtd/mtd.h>
#include <nand.h>
#include <netdev.h>
#include <mmc.h>
#include <asm/sections.h>
#include <sdhci.h>

#ifndef CONFIG_SYS_DCACHE_OFF
void enable_caches(void)
{
    /* Enable D-cache. I-cache is already enabled in start.S */
    dcache_enable();
}
#endif
static int boot_media = BOOT_MEDIA_UNKNOWN;
int get_boot_media(void)
{
    unsigned int reg_val, boot_mode, spi_device_mode;
    int boot_media = BOOT_MEDIA_UNKNOWN;

    reg_val = readl(SYS_CTRL_REG_BASE + REG_SYSSTAT);
    boot_mode = GET_SYS_BOOT_MODE(reg_val);

    switch (boot_mode) {
        case BOOT_FROM_SPI:
            spi_device_mode = GET_SPI_DEVICE_TYPE(reg_val);
            if (spi_device_mode) {
                boot_media = BOOT_MEDIA_NAND;
            } else {
                boot_media = BOOT_MEDIA_SPIFLASH;
            }
            break;
        case BOOT_FROM_EMMC:
            boot_media = BOOT_MEDIA_EMMC;
            break;
        default:
            boot_media = BOOT_MEDIA_UNKNOWN;
            break;
    }

    return boot_media;
}

#if defined(CONFIG_SHOW_BOOT_PROGRESS)
void show_boot_progress(int progress)
{
    printf("Boot reached stage %d\n", progress);
}
#endif

#define COMP_MODE_ENABLE ((unsigned int)0x0000EAEF)

static inline void delay(unsigned long loops)
{
    __asm__ volatile ("1:\n"
                      "subs %0, %1, #1\n"
                      "bne 1b" : "=r" (loops) : "0" (loops));
}

/* get uboot start media. */
/*int get_boot_media(void)
{
    return boot_media;
}*/

int get_text_base(void)
{
    return CONFIG_SYS_TEXT_BASE;
}

static void boot_flag_init(void)
{
    unsigned int reg, boot_mode, spi_device_mode;

    /* get boot mode */
    reg = __raw_readl(SYS_CTRL_REG_BASE + REG_SYSSTAT);
    boot_mode = GET_SYS_BOOT_MODE(reg);

    switch (boot_mode) {
        case BOOT_FROM_SPI:
            spi_device_mode = GET_SPI_DEVICE_TYPE(reg);
            if (spi_device_mode) {
                boot_media = BOOT_MEDIA_NAND;
            } else {
                boot_media = BOOT_MEDIA_SPIFLASH;
            }
            break;
        case BOOT_FROM_EMMC:    /* emmc mode */
            boot_media = BOOT_MEDIA_EMMC;
            break;
        default:
            boot_media = BOOT_MEDIA_UNKNOWN;
            break;
    }
}

int board_early_init_f(void)
{
    return 0;
}

#define UBOOT_DATA_ADDR     (0x41000000)
#define UBOOT_DATA_SIZE     (0x80000)
int save_bootdata_to_flash(void)
{
    unsigned int sd_update_flag;
    void *buf = NULL;

    sd_update_flag = readl(REG_BASE_SCTL + REG_SC_GEN4);
    if (sd_update_flag == START_MAGIC) {
#if defined(CONFIG_HIFMC)
        static struct spi_flash *flash;
        unsigned int val;
        if (boot_media == BOOT_MEDIA_SPIFLASH) {
            flash = spi_flash_probe(0, 0, 1000000, 0x3);
            if (!flash) {
                printf("Failed to initialize SPI flash\n");
                return -1;
            }

            /* erase the address range. */
            printf("Spi flash erase...\n");
            val = flash->erase(flash, 0, UBOOT_DATA_SIZE);
            if (val) {
                printf("SPI flash sector erase failed\n");
                return 1;
            }

            buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
                              UBOOT_DATA_SIZE, MAP_WRBACK);
            if (!buf) {
                puts("Failed to map physical memory\n");
                return 1;
            }

            /* copy the data from RAM to FLASH */
            printf("Spi flash write...\n");
            val = flash->write(flash, 0, UBOOT_DATA_SIZE, buf);
            if (val) {
                printf("SPI flash write failed, return %d\n",
                       val);
                unmap_physmem(buf, UBOOT_DATA_SIZE);
                return 1;
            }

            unmap_physmem(buf, UBOOT_DATA_SIZE);
        }
        if (boot_media == BOOT_MEDIA_NAND) {
            struct mtd_info *nand_flash;
            size_t length = UBOOT_DATA_SIZE;

            nand_flash = nand_info[0];

            printf("Nand flash erase...\n");
            val = nand_erase(nand_flash, 0, UBOOT_DATA_SIZE);
            if (val) {
                printf("Nand flash erase failed\n");
                return 1;
            }

            buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
                              UBOOT_DATA_SIZE, MAP_WRBACK);
            if (!buf) {
                puts("Failed to map physical memory\n");
                return 1;
            }

            printf("Nand flash write...\n");
            val = nand_write(nand_flash, 0, &length, buf);
            if (val) {
                printf("Nand flash write failed, return %d\n",
                       val);
                unmap_physmem(buf, UBOOT_DATA_SIZE);
                return 1;
            }

            unmap_physmem(buf, UBOOT_DATA_SIZE);
        }
#endif
#if defined(CONFIG_SUPPORT_EMMC_BOOT)
        if (boot_media == BOOT_MEDIA_EMMC) {
            struct mmc *mmc = find_mmc_device(0);

            if (!mmc) {
                return 1;
            }

            (void)mmc_init(mmc);

            buf = map_physmem((unsigned long)UBOOT_DATA_ADDR,
                              UBOOT_DATA_SIZE, MAP_WRBACK);
            if (!buf) {
                puts("Failed to map physical memory\n");
                return 1;
            }

            printf("MMC write...\n");
            blk_dwrite(mmc_get_blk_desc(mmc), 0, (UBOOT_DATA_SIZE >> 9), buf);
            unmap_physmem(buf, UBOOT_DATA_SIZE);
        }
#endif

        printf("update success!\n");
    }

    return 0;
}

int auto_update_flag = 0;
int bare_chip_program = 0;

#define REG_BASE_GPIO0          0x120b0000
#define GPIO0_0_DATA_OFST       0x4
#define GPIO_DIR_OFST       0x400

/** upgrade status register address */
#define UPGRADE_STATUS_REG_ADDR (0x120F0048)

typedef enum tagUPGRADE_STATUS_E {
    UPGRADE_STATUS_IDLE = 0,
    UPGRADE_STATUS_PROCESSING,
    UPGRADE_STATUS_FINISH,
    UPGRADE_STATUS_BUTT
} UPGRADE_STATUS_E;

int is_bare_program(void)
{
    return 1;
}

int is_auto_update(void)
{
#if (defined CONFIG_AUTO_SD_UPDATE) || (defined CONFIG_AUTO_USB_UPDATE)
    /* to add some judgement if neccessary */
    unsigned int  val[3];

    unsigned int* puregval = (unsigned int*)UPGRADE_STATUS_REG_ADDR;
    if (((*puregval)&(UPGRADE_STATUS_PROCESSING)) != 0)
    {
        return 1; /* update enable */
    }

    writel(REG_BASE_GPIO0 + GPIO_DIR_OFST, 0);

    val[0] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
    if(val[0]) {
        return 0;
    }

    udelay(10000);
    val[1] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
    udelay(10000);
    val[2] = readl(REG_BASE_GPIO0 + GPIO0_0_DATA_OFST);
    udelay(10000);

    if (val[0] == val[1] && val[1] == val[2] && val[0] == 0) {
        return 1;    /* update enable */
    } else {
        return 0;
    }

#else
    return 0;
#endif
}

int misc_init_r(void)
{
#ifdef CONFIG_RANDOM_ETHADDR
    random_init_r();
#endif
    setenv("verify", "n");

#ifdef CONFIG_AUTO_UPDATE
    /* auto update flag */
    if(is_auto_update()) {
        auto_update_flag = 1;
    } else {
        auto_update_flag = 0;
    }

    /* bare chip program flag */
    if(is_bare_program()) {
        bare_chip_program = 1;
    } else {
        bare_chip_program = 0;
    }

#ifdef CFG_MMU_HANDLEOK
    dcache_stop();
#endif

#ifdef CFG_MMU_HANDLEOK
    dcache_start();
#endif

#endif

#ifdef CONFIG_AUTO_UPDATE
    int update_flag = -1;
    extern int do_auto_update(void);
    if (auto_update_flag) {
#ifdef CONFIG_EMMC
        extern int target_dev;
        extern int target_paratition;
        unsigned int uval = readl(UPGRADE_STATUS_REG_ADDR);
        unsigned int stor_dev = 0;
        unsigned int stor_paration = 0;
        stor_dev = (uval >> 16) & 0x03;
        stor_paration = (uval >> 18) & 0x1f;
        if(((uval)&(UPGRADE_STATUS_PROCESSING)) != 0) {
            //the upgrade startup by linux application
            if(stor_dev == 0) {
                target_dev = 0; //emmc
                target_paratition = stor_paration;
            } else {
                target_dev = 1; //sd
                target_paratition = 0;
            }
        } else {
            //the upgrade startup by upgrade key on the board
            target_dev = 0; //emmc
            target_paratition = -1;
        }

        printf("update dev is %d: paratition is %d\n", target_dev, target_paratition);
#endif
        update_flag = do_auto_update();
        unsigned int* puregval = (unsigned int*)UPGRADE_STATUS_REG_ADDR;
        if (((*puregval) & (UPGRADE_STATUS_PROCESSING)) && (update_flag == 0)) {
            printf("upgrade status: finish\n");
            *puregval = UPGRADE_STATUS_FINISH;
        }
    }
    if (bare_chip_program && !auto_update_flag) {
        save_bootdata_to_flash();
    }
    extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
    if (update_flag == 0) {
        do_reset(NULL, 0, 0, NULL);
    }
#endif
    return 0;
}

#define reg_gpio_base				(0x120b0000)
#define reg_iocfg_vio_base			(0x112c0000)
#define reg_crg_base				(0x12010000)
#define SYS_WRITEL(addr, val) 		writel(val, addr)
#define SYS_READ(addr)				readl(addr)
#define GPIO_BANK_BASE(bank)		(reg_gpio_base + 0x1000*bank)
#define GPIO_DIR_OFFSET				(0x400)
#define GPIO_VALUE_OFFSET			(0)

#define SSP_BASE    0x12070000
#define SSP_SIZE    0x1000          // 4KB

#define IO_ADDRESS_VERIFY(x) (x)


/* SSP register definition .*/
#define SSP_CR0              IO_ADDRESS_VERIFY(SSP_BASE + 0x00)
#define SSP_CR1              IO_ADDRESS_VERIFY(SSP_BASE + 0x04)
#define SSP_DR               IO_ADDRESS_VERIFY(SSP_BASE + 0x08)
#define SSP_SR               IO_ADDRESS_VERIFY(SSP_BASE + 0x0C)
#define SSP_CPSR             IO_ADDRESS_VERIFY(SSP_BASE + 0x10)
#define SSP_IMSC             IO_ADDRESS_VERIFY(SSP_BASE + 0x14)
#define SSP_RIS              IO_ADDRESS_VERIFY(SSP_BASE + 0x18)
#define SSP_MIS              IO_ADDRESS_VERIFY(SSP_BASE + 0x1C)
#define SSP_ICR              IO_ADDRESS_VERIFY(SSP_BASE + 0x20)
#define SSP_DMACR            IO_ADDRESS_VERIFY(SSP_BASE + 0x24)

#define SPI_SR_BSY        (0x1 << 4)/* spi busy flag */
#define SPI_SR_TFE        (0x1 << 0)/* Whether to send fifo is empty */
#define SPI_DATA_WIDTH    (9)
#define SPI_SPO           (1)
#define SPI_SPH           (1)
#define SPI_SCR           (8)
#define SPI_CPSDVSR       (8)
#define SPI_FRAMEMODE     (0)

#define MAX_WAIT 10000

#define  ssp_readw(addr,ret)            (ret =(*(volatile unsigned int *)(addr)))
#define  ssp_writew(addr,value)            ((*(volatile unsigned int *)(addr)) = (value))

static int ssp_set_reg(unsigned int Addr, unsigned int Value)
{
    (*(volatile unsigned int *)(Addr)) = Value;
    return 0;
}

static int hi_spi_check_timeout(void)
{
    unsigned int value =  0;
    unsigned int tmp = 0;
    while (1)
    {
        ssp_readw(SSP_SR,value);
        if ((value & SPI_SR_TFE) && (!(value & SPI_SR_BSY)))
        {
            break;
        }

        if (tmp++ > MAX_WAIT)
        {
            printk("spi transfer wait timeout!\n");
            return -1;
        }
        udelay(1);
    }
    return 0;
}



static void hi_ssp_writeOnly(int bWriteOnly)
{
    unsigned int  ret = 0;
    
    ssp_readw(SSP_CR1,ret);

    if (bWriteOnly)
    {
        ret = ret | (0x1 << 5);
    }
    else
    {
        ret = ret & (~(0x1 << 5));
    }

    ssp_writew(SSP_CR1,ret);
}


static void hi_ssp_enable(void)
{
    unsigned int ret = 0;
    ssp_readw(SSP_CR1,ret);
    ret = (ret & 0xFFFD) | 0x2;

    ret = ret | (0x1 << 4); /* big/little end, 1: little, 0: big */

    ret = ret | (0x1 << 15); /* wait en */

    ssp_writew(SSP_CR1,ret);

    hi_ssp_writeOnly(0);
}


static void hi_ssp_disable(void)
{
    unsigned int ret = 0;
    ssp_readw(SSP_CR1,ret);
    ret = ret & (~(0x1 << 1));
    ssp_writew(SSP_CR1,ret);
}

static int hi_ssp_set_frameform(unsigned char framemode,unsigned char spo,unsigned char sph,unsigned char datawidth)
{
    unsigned int ret = 0;
    ssp_readw(SSP_CR0,ret);
    if(framemode > 3)
    {
        printk("set frame parameter err.\n");
        return -1;
    }
    ret = (ret & 0xFFCF) | (framemode << 4);
    if((ret & 0x30) == 0)
    {
        if(spo > 1)
        {
            printk("set spo parameter err.\n");
            return -1;
        }
        if(sph > 1)
        {
            printk("set sph parameter err.\n");
            return -1;
        }
        ret = (ret & 0xFF3F) | (sph << 7) | (spo << 6);
    }
    if((datawidth > 16) || (datawidth < 4))
    {
        printk("set datawidth parameter err.\n");
        return -1;
    }
    ret = (ret & 0xFFF0) | (datawidth -1);
    ssp_writew(SSP_CR0,ret);
    return 0;
}


static int hi_ssp_set_serialclock(unsigned char scr,unsigned char cpsdvsr)
{
    unsigned int ret = 0;
    ssp_readw(SSP_CR0,ret);
    ret = (ret & 0xFF) | (scr << 8);
    ssp_writew(SSP_CR0,ret);
    if((cpsdvsr & 0x1))
    {
        printk("set cpsdvsr parameter err.\n");
        return -1;
    }
    ssp_writew(SSP_CPSR,cpsdvsr);
    return 0;
}

static int hi_ssp_alt_mode_set(int enable)
{
    unsigned int ret = 0;

    ssp_readw(SSP_CR1,ret);
    if (enable)
    {
        ret = ret & (~0x40);
    }
    else
    {
        ret = (ret & 0xFF) | 0x40;
    }
    ssp_writew(SSP_CR1,ret);

    return 0;
}

static void spi_enable(void)
{
    ssp_writew(SSP_CR1, 0x42);
}

static void spi_disable(void)
{
    ssp_writew(SSP_CR1, 0x40);
}

static void spi_write_a9byte(unsigned char cmd_dat,unsigned char dat)
{
    unsigned short spi_data = 0;
    int ret = 0;
    if(cmd_dat)
    {
        spi_data = 1 << 8;
    }
    else
    {
        spi_data = 0 << 8;
    }

    spi_data = spi_data | dat;
    spi_enable();
    ssp_writew(SSP_DR,spi_data);
    ret =  hi_spi_check_timeout();
    if(ret != 0)
    {
        printk("spi_send timeout\n");
    }
    spi_disable();
}

static void ssp_write_dat(unsigned char dat)
{
    spi_write_a9byte(1,dat);
}

static void ssp_write_cmd(unsigned char dat)
{
    spi_write_a9byte(0,dat);
}

static void ssp_set(void)
{
    spi_disable();
    hi_ssp_set_frameform(SPI_FRAMEMODE, SPI_SPO, SPI_SPH, SPI_DATA_WIDTH);
    hi_ssp_set_serialclock(SPI_SCR, SPI_CPSDVSR);
    hi_ssp_alt_mode_set(1);
    hi_ssp_enable();
}


static inline void reg_write32(unsigned long value, unsigned long mask,const void *addr)
{
    unsigned long t;

    t = SYS_READ((const volatile void *)addr);
    t &= ~mask;
    t |= value & mask;
    SYS_WRITEL((volatile void *)addr, t);
}


void gpio_set_dir(unsigned long bank, unsigned long pin, unsigned long isout)
{
	if (isout)
	{
		reg_write32(1<<pin, 1<<pin, GPIO_BANK_BASE(bank) + GPIO_DIR_OFFSET);
	}
	else
	{
		reg_write32(0<<pin, 1<<pin, GPIO_BANK_BASE(bank) + GPIO_DIR_OFFSET);
	}
	
}

void gpio_set_val(unsigned long bank, unsigned long pin, unsigned long ishigh)
{
	if (ishigh)
	{
		reg_write32(1<<pin, 1<<pin, GPIO_BANK_BASE(bank) + GPIO_VALUE_OFFSET + (1 << ((pin) + 2)));
	}
	else
	{
		reg_write32(0<<pin, 1<<pin, GPIO_BANK_BASE(bank) + GPIO_VALUE_OFFSET + (1 << ((pin) + 2)));
	}
}

void spi0_pin_mux_18ev300(void)
{
	reg_write32(0x1 << 12, 0x1 << 12, reg_crg_base+0x01bc); /* SPI0 clock for LCD*/
	SYS_WRITEL(reg_iocfg_vio_base+0x0038, 0x1077);			/* SPI0_SDO */
	SYS_WRITEL(reg_iocfg_vio_base+0x003C, 0x1407);			/* SPI0_CLK */
	SYS_WRITEL(reg_iocfg_vio_base+0x0040, 0x1077);			/* SPI0_CS */
}


void vo_6bit_lcd_for_sckb_mux_18ev300(void)
{
    SYS_WRITEL(reg_iocfg_vio_base+0x0048, 0x1A55);
    SYS_WRITEL(reg_iocfg_vio_base+0x0074, 0x1075);
    SYS_WRITEL(reg_iocfg_vio_base+0x0070, 0x1035);
    SYS_WRITEL(reg_iocfg_vio_base+0x006C, 0x1035);
    SYS_WRITEL(reg_iocfg_vio_base+0x0068, 0x1035);
    SYS_WRITEL(reg_iocfg_vio_base+0x0058, 0x1035);
    SYS_WRITEL(reg_iocfg_vio_base+0x005C, 0x1035);
    
    SYS_WRITEL(reg_iocfg_vio_base+0x0054, 0x1A35);
    SYS_WRITEL(reg_iocfg_vio_base+0x004c, 0x1035);
    SYS_WRITEL(reg_iocfg_vio_base+0x0050, 0x1035);

	/* gpio7_2 , lcd_cs */
	SYS_WRITEL(reg_iocfg_vio_base+0x0060, 0x0);
	gpio_set_dir(7, 2, 1);
	gpio_set_val(7, 2, 0);
	/* gpio7_3 , lcd_rst */
    SYS_WRITEL(reg_iocfg_vio_base+0x0064, 0x0);
	printf("reset lcd\n");
	gpio_set_dir(7, 3, 1);
	gpio_set_val(7, 3, 0);
	udelay(100);
	gpio_set_val(7, 3, 1);
}

static void lcd_st7789_init_vertical(void)
{
	/*spi_9bit_setting*/
	ssp_set();

	ssp_write_cmd(0x11);
	udelay(120*1000);
	//--------------------------------ST7789S Memory Data Access Control setting----------------------------------//
	//-----------------------Decides RGB/BGR or refresh Left to Right/Bottom to Top and so on---------------------- ---//
#if 0
	ssp_write_cmd(0x36);
	ssp_write_dat(0x00);

	//----------------------------------ST7789S Interface Pixel Format setting--------------------------------------//
	//----------------------------------18bit/Pixel and 262K of RGB interface----------------------------------------//
	ssp_write_cmd(0x3A);
	ssp_write_dat(0x66);
	//----------------------------------------ST7789S Display InversionOn Cmd-------------------------------------//
	ssp_write_cmd(0x21);

	//------------------------------------------ST7789S RAM Control Setting---------------------------------------//
	ssp_write_cmd(0xB0);
	ssp_write_dat(0x11);
	ssp_write_dat(0x04);

	//---------------------------------------ST7789S RAM Interface Control Setting----------------------------------//
	//----------------------------------------RGB Mode:Shift Register----------------------------------------------//
	ssp_write_cmd(0xB1);
	ssp_write_dat(0xC0);
	ssp_write_dat(0x02);
	ssp_write_dat(0x14);

	//-----------------------------------------ST7789S Porch Setting---------------------------------------------//
	ssp_write_cmd(0xB2);
	ssp_write_dat(0x05);
	ssp_write_dat(0x05);
	ssp_write_dat(0x00);
	ssp_write_dat(0x33);
	ssp_write_dat(0x33);

	//-----------------------------------------ST7789S Gate Control Setting----------------------------------------//
	//--------------------------------------------VGL and VGH number--------------------------------------------//
	ssp_write_cmd(0xB7);
	ssp_write_dat(0x64);

	//-----------------------------------------ST7789S VCOM  setting---------------------------------------------//
	ssp_write_cmd(0xBB);
	ssp_write_dat(0x25);

	//---------------------------------------ST7789S LCM Control setting-------------------------------------------//
	ssp_write_cmd(0xC0);
	ssp_write_dat(0x2C);

	//-----------------------------------ST7789S VDV and VRH Command Enable setting--------------------------------//
	ssp_write_cmd(0xC2);
	ssp_write_dat(0x01);

	ssp_write_cmd(0xC3);
	//ssp_write_dat(0x13);
	ssp_write_dat(0x20);

	ssp_write_cmd(0xC4);
	//ssp_write_dat(0x20);
	ssp_write_dat(0x3);
	//----------------------------------ST7789S Normal mode Frame Rate setting--------------------------------------//
	ssp_write_cmd(0xC6);
	ssp_write_dat(0x11);

	//-------------------------------------ST7789S Power Control setting--------------------------------------------//
	ssp_write_cmd(0xD0);
	ssp_write_dat(0xA4);
	ssp_write_dat(0xA1);

	ssp_write_cmd(0xD6);
	ssp_write_dat(0xA1);

	//---------------------------------ST7789S Positive Gamma setting--------------------------------------//
#if 0
	ssp_write_cmd(0xE0);
	ssp_write_dat(0xd0);
	ssp_write_dat(0x00);
	ssp_write_dat(0x00);
	ssp_write_dat(0x08);
	ssp_write_dat(0x11);
	ssp_write_dat(0x1a);
	ssp_write_dat(0x2b);
	ssp_write_dat(0x33);
	ssp_write_dat(0x42);
	ssp_write_dat(0x26);
	ssp_write_dat(0x12);
	ssp_write_dat(0x21);
	ssp_write_dat(0x2f);
	ssp_write_dat(0x11);

	//---------------------------------ST7789S Negative Gamma setting--------------------------------------//
	ssp_write_cmd(0xE1);
	ssp_write_dat(0xd0);
	ssp_write_dat(0x02);
	ssp_write_dat(0x09);
	ssp_write_dat(0x0d);
	ssp_write_dat(0x0d);
	ssp_write_dat(0x27);
	ssp_write_dat(0x2b);
	ssp_write_dat(0x33);
	ssp_write_dat(0x42);
	ssp_write_dat(0x17);
	ssp_write_dat(0x12);
	ssp_write_dat(0x11);
	ssp_write_dat(0x2f);
	ssp_write_dat(0x31);
#endif
	//-----------------------------------ST7789S BrightNess Setting------------------------------------------//
	//ssp_write_cmd(0x51);
	//ssp_write_dat(0xFF);

	//-----------------------------------ST7789S Display ON Cmd--------------------------------------------//
	ssp_write_cmd(0x29);

	//-----------------------------------ST7789S Memory Write Cmd-----------------------------------------//
	//--------------------------------Transfer data from MCU to Frame memory---------------------------------//
	ssp_write_cmd(0x2c);

#else
	//--------------------------------ST7789S Frame rate setting----------------------------------//
	ssp_write_cmd(0x36);
	ssp_write_dat(0x00);
	//--------------------------------ST7789S Frame rate setting----------------------------------//
	ssp_write_cmd(0xb2);
	ssp_write_dat(0x00);
	ssp_write_dat(0x00);
	ssp_write_dat(0x00);
	ssp_write_dat(0x33);
	ssp_write_dat(0x33);

	ssp_write_cmd(0xb7);
	ssp_write_dat(0x35);
	//---------------------------------ST7789S Power setting--------------------------------------//
	ssp_write_cmd(0xb8);
	ssp_write_dat(0x2f);
	ssp_write_dat(0x2b);
	ssp_write_dat(0x2f);

	ssp_write_cmd(0xbb);
	ssp_write_dat(0x24);//vcom

	ssp_write_cmd(0xc0);
	ssp_write_dat(0x2C);

	ssp_write_cmd(0xc3);
	ssp_write_dat(0x20);

	ssp_write_cmd(0xc4);
	ssp_write_dat(0x3);

	ssp_write_cmd(0xc6);
	ssp_write_dat(0x11);

	ssp_write_cmd(0xd0);
	ssp_write_dat(0xa4);
	ssp_write_dat(0xa1);

	ssp_write_cmd(0xe8);
	ssp_write_dat(0x03);

	ssp_write_cmd(0xe9);
	ssp_write_dat(0x0d);
	ssp_write_dat(0x12);
	ssp_write_dat(0x00);
	//--------------------------------ST7789S gamma setting---------------------------------------//
#if 0
	ssp_write_cmd(0xe0);
	ssp_write_dat(0xd0);
	ssp_write_dat(0x00);
	ssp_write_dat(0x00);
	ssp_write_dat(0x08);
	ssp_write_dat(0x11);
	ssp_write_dat(0x1a);
	ssp_write_dat(0x2b);
	ssp_write_dat(0x33);
	ssp_write_dat(0x42);
	ssp_write_dat(0x26);
	ssp_write_dat(0x12);
	ssp_write_dat(0x21);
	ssp_write_dat(0x2f);
	ssp_write_dat(0x11);

	ssp_write_cmd(0xe1);
	ssp_write_dat(0xd0);
	ssp_write_dat(0x02);
	ssp_write_dat(0x09);
	ssp_write_dat(0x0d);
	ssp_write_dat(0x0d);
	ssp_write_dat(0x27);
	ssp_write_dat(0x2b);
	ssp_write_dat(0x33);
	ssp_write_dat(0x42);
	ssp_write_dat(0x17);
	ssp_write_dat(0x12);
	ssp_write_dat(0x11);
	ssp_write_dat(0x2f);
	ssp_write_dat(0x31);
#endif
	ssp_write_cmd(0x20);

	//*********SET RGB Interfae***************
	ssp_write_cmd(0xB0);
	ssp_write_dat(0x11); //set RGB interface and DE mode.
	ssp_write_dat(0x04);
	ssp_write_dat(0x00);

	ssp_write_cmd(0xB1);
	ssp_write_dat(0xc0); //set DE mode ; SET Hs,Vs,DE,DOTCLK signal polarity
	ssp_write_dat(0x02);  //ori 2
	ssp_write_dat(0x14); //ori 14
	
	ssp_write_cmd(0x3a);
	ssp_write_dat(0x55); //18 RGB ,55-16BIT RGB
	ssp_write_cmd(0x11); //Exit Sleep
	ssp_write_cmd(0x29); //display on
	ssp_write_cmd(0x2c);
#endif
	return;
}


static int hi_ssp_lcd_st7789_init(void)
{
	lcd_st7789_init_vertical();
}


int board_late_init(void)
{
	/* spi0 */
	//printf("set spi0 pinmux \n");
	spi0_pin_mux_18ev300();

	/* lcd */
	//printf("set lcd pinmux \n");
	vo_6bit_lcd_for_sckb_mux_18ev300();

	/* st7789v init */
	printf("st7789v init \n");
	hi_ssp_lcd_st7789_init();

	udelay(1000*100);
	run_command("sf probe 0", 0);
	run_command("sf read 0x47c00000 0x700000 0x100000", 0);
	run_command("startvo 0 512 47", 0);
	run_command("startgx 0 0x47c00000 480 0 0 240 320", 0);
	return 0;
}

int board_init(void)
{
    DECLARE_GLOBAL_DATA_PTR;

    gd->bd->bi_arch_number = MACH_TYPE_HI3518EV300;
    gd->bd->bi_boot_params = CFG_BOOT_PARAMS;

    boot_flag_init();

    return 0;
}

int dram_init(void)
{
    DECLARE_GLOBAL_DATA_PTR;

    gd->ram_size = PHYS_SDRAM_1_SIZE;
    return 0;
}

void reset_cpu(ulong addr)
{
    writel(0x12345678, REG_BASE_SCTL + REG_SC_SYSRES);
    while(1);
}

int timer_init(void)
{
    /*
     **Under uboot, 0xffffffff is set to load register,
     ** timer_clk = BUSCLK/2/256.
     ** e.g. BUSCLK = 50M, it will roll back after 0xffffffff/timer_clk
     ** = 43980s = 12hours
     **/
    __raw_writel(0, CFG_TIMERBASE + REG_TIMER_CONTROL);
    __raw_writel(~0, CFG_TIMERBASE + REG_TIMER_RELOAD);

    /*32 bit, periodic*/
    __raw_writel(CFG_TIMER_CTRL, CFG_TIMERBASE + REG_TIMER_CONTROL);

    return 0;
}

int board_eth_init(bd_t *bis)
{
    int rc = 0;

#ifdef CONFIG_NET_HISFV300
    rc = hieth_initialize(bis);
#endif
    return rc;
}

#ifdef CONFIG_GENERIC_MMC
extern int hisi_sdhci_add_port(int index, u32 regbase, u32 type);
extern int hisi_mmc_init(int index);

int board_mmc_init(bd_t *bis)
{
    int ret = 0;

#ifdef CONFIG_HISI_SDHCI

#ifndef CONFIG_HIFMC
    ret = hisi_sdhci_add_port(0, EMMC_BASE_REG, MMC_TYPE_MMC);
    if (!ret) {
        ret = hisi_mmc_init(0);
        if (ret) {
            printf("No EMMC device found !\n");
        }
    }
#else

#ifdef CONFIG_AUTO_SD_UPDATE
    ret = hisi_sdhci_add_port(0, SDIO0_BASE_REG, MMC_TYPE_SD);
    if (ret) {
        return ret;
    }

    ret = hisi_mmc_init(0);
    if (ret) {
        printf("No SD device found !\n");
    }
#endif

#endif
#endif

    return ret;
}
#endif
#ifdef CONFIG_ARMV7_NONSEC
void smp_set_core_boot_addr(unsigned long addr, int corenr)
{
}

void smp_kick_all_cpus(void)
{
}

void smp_waitloop(unsigned previous_address)
{
}
#endif

